package com.example.codequalityservice.task;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.fastjson.JSON;
import com.example.api.service.CallbackService;
import com.example.api.service.CodeQualityService;
import com.example.common.config.ThreadPool;
import com.example.common.constant.Constants;
import com.example.common.entity.*;
import com.example.common.mapper.CodeQualityResultMapper;
import com.example.common.utils.PythonScriptCallable;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

/**
 * @author DestinyCc
 * @date 2022/4/16
 */
@Slf4j
@Component
@EnableScheduling
@EnableAsync
public class Task {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    CodeQualityResultMapper codeQualityResultMapper;

    @Reference
    CallbackService callbackService;

    @Reference
    CodeQualityService codeQualityService;

    @Scheduled(fixedDelay = 5000)
    @Async
    @SneakyThrows
    public void calculateCodeQualityTask(){
        if (stringRedisTemplate.opsForList().size(Constants.CODE_QUALITY_CAL_MSG_NAME) != 0){
            String jsonStr = stringRedisTemplate.opsForList().leftPop(Constants.CODE_QUALITY_CAL_MSG_NAME);
            CodeQualityCalMsg calMsg = JSON.parseObject(jsonStr, CodeQualityCalMsg.class);
            //cal previous 8 criterion
            log.info("msg = {}", JSON.toJSONString(calMsg));
            PythonScriptCallable codeQuality = new PythonScriptCallable(calMsg.getCodeQualityCmd());
            PythonScriptCallable codeReliability = new PythonScriptCallable(calMsg.getReliabilityCmd());
            FutureTask<String> codeQualityTask = new FutureTask<>(codeQuality);
            FutureTask<String> codeReliabilityTask = new FutureTask<>(codeReliability);
            log.info("starting task1");
            ThreadPool.executor.submit(codeQualityTask);
            log.info("starting task2");
            ThreadPool.executor.submit(codeReliabilityTask);
            while (! codeQualityTask.isDone()){
                TimeUnit.SECONDS.sleep(1);
            }
            while (! codeReliabilityTask.isDone()){
                TimeUnit.SECONDS.sleep(1);
            }
            String filename = codeQualityTask.get();
            String reliability = codeReliabilityTask.get();
            log.info("filename = {}", filename);
            List<CodeQuality> codeQualities = new ArrayList<>();
            List<String> filenames = new ArrayList<>();
            EasyExcel.read(Constants.CODE_QUALITY_PROJECT_LOCATION + filename, CodeQualityXlsx.class, new PageReadListener<CodeQualityXlsx>(dataList -> {
                for (CodeQualityXlsx quality : dataList) {
                    log.info("读取到一条数据{}", JSON.toJSONString(quality));
                    if (! filenames.contains(quality.getFilename())){
                        filenames.add(quality.getFilename());
                        codeQualities.add(CodeQuality.builder()
                                .filename(quality.getFilename())
                                .reuseablity(Double.parseDouble(quality.getReusability()))
                                .complexity(Double.parseDouble(quality.getComplexity()))
                                .extendability(Double.parseDouble(quality.getExtendibility()))
                                .inheritance(Double.parseDouble(quality.getInheritance()))
                                .maintainability(Double.parseDouble(quality.getMaintainability()))
                                .readability(Double.parseDouble(quality.getReadability()))
                                .security(Double.parseDouble(quality.getSecurity()))
                                .testability(Double.parseDouble(quality.getTestablity()))
                                .build());
                    }
                }
            })).sheet().doRead();
            AvgQuality avgQuality = new AvgQuality(reliability);
            codeQualities.forEach(avgQuality::addOneValue);
            avgQuality = avgQuality.getAvgCodeQuality(codeQualities.size());
            //更新数据库
            CodeQualityResult codeQualityResult = codeQualityService.getCodeQualityResult(calMsg.getResultId(), calMsg.getTenantId());
            codeQualityResult.setComplexity(avgQuality.getComplexity());
            codeQualityResult.setExtendability(avgQuality.getExtendability());
            codeQualityResult.setInheritance(avgQuality.getInheritance());
            codeQualityResult.setMaintainability(avgQuality.getMaintainability());
            codeQualityResult.setReadability(avgQuality.getReadability());
            codeQualityResult.setReliability(avgQuality.getReliability());
            codeQualityResult.setReuseablity(avgQuality.getReuseablity());
            codeQualityResult.setSecurity(avgQuality.getSecurity());
            codeQualityResult.setTestability(avgQuality.getTestability());
            codeQualityResultMapper.updateByPrimaryKeySelective(codeQualityResult);
            //开始回调
            callbackService.doCallback(avgQuality, calMsg.getTenantId(), calMsg.getAppId(), Constants.CallbackEvent.CODE_QUALITY_CAL_RES);
        }
    }
}
